import { defineStore } from "pinia";
import { getToken, removeToken, setToken } from "../utils/token-utils";
import { requestLogin, requestUserInfo, requestLogout } from "@/api/userInfo";
import type { reqLoginParamType, reqUserInfoReturnType } from "@/api/userInfo";
import { staticRoutes,allAsyncRoutes, anyRoute } from "@/router/routes";
import type { RouteRecordRaw } from "vue-router";
import router from "@/router";
import { cloneDeep } from "lodash";

// 过滤动态路由中，需要展示的路由菜单，并收集起来（返回出去），接由两个参数，1.完整的动态路由数组 2.当前用户信息的routes
  function filterAsyncRoutes(
    allAsyncRoutes: RouteRecordRaw[],
    routeNames:string[]
  ) {
    return allAsyncRoutes.filter((item) =>{
      if(routeNames.includes(item.name as string)) {
      //符合条件的item中可能有二级路由,再次判断(递归!!!!!)
      if (item.children && item.children.length) {
      //此时当前一级路由已经顺利通过检测了,但是还是要看它内部的二级路由是否符合,
      //把item.children拿进来判断,最后得到过滤结果之后,直接替换item.children
       item.children = filterAsyncRoutes(
        item.children as RouteRecordRaw [],
        routeNames
       );
      }
      return true;
      } 
    });
  }

  // 2.把根据用户信息过滤出来的动态由数组，和任意由全部放入静态路由中
  function addRoutes(routes: RouteRecordRaw[]) {
  //router只有addRoute方法，所以我们需要遍历动态路由依次插入
  routes.forEach((item)=>{
      //因为此时router已经作用于app应用实例上了，再直接去修改staticRoutes是不管用的（只能修改菜单）
    //所以我们需要使用router的addRoute给已经注册的路由器添加新的路由
    router.addRoute(item);
  });
  }

  //3.封装一个退出登录后 对动态路由的清理
function resetRoutes(staticRoutes: RouteRecordRaw[]) {
  //退出登录的时候，把路由器中的路由全部清理掉
  // 获取所有 路由记录的完整列表
  const routes = router.getRoutes();
  //遍历routes清理路由
  routes.forEach((item) => {
    if (item.name) {
      router.removeRoute(item.name);
    }
  });
  //清理完所有的路由，然后把静态路由再插入回去
  addRoutes(staticRoutes);
}


/**
 * 用户信息
 * @methods setUserInfos 设置用户信息
 */

//当前userInfo的小仓库的state类型限制
export interface UserInfoState {
  token: string;
  //userInfo的值是请求回来的,所以类型直接设置为请求的返回值类型
  userInfo: reqUserInfoReturnType;
  menuRoutes: RouteRecordRaw[];
}

export const useUserInfoStore = defineStore("userInfo", {
  state: (): UserInfoState => ({
    token: (getToken() as string) || "",
    userInfo: {
      routes: [],
      buttons: [],
      roles: [],
      name: "",
      avatar: "",
    },
    //把静态路由表保存起来,侧边栏其实是拿到这个路由表,然后遍历生成侧边栏元素的
    menuRoutes: staticRoutes,
  }),

  actions: {
    //登录的方法
    async login(loginParam: reqLoginParamType) {
      try {
        //发送登录请求
        const result = await requestLogin(loginParam);
        //拿到结果token设置给state中
        this.token = result.token;
        //设置自动登录(持久化保存token)
        setToken(this.token);
      } catch (e) {
        //如果将来调用这个login方法时,请求出现问题，则返回一个失败的promise实例，在哪调用的这个login 再哪里处理
        return Promise.reject(e);
      }
    },

    //用户信息请求的方法
    async getInfo() {
      try {
        //发送用户信息请求
        const result = await requestUserInfo();
        //把数据交给state
        this.userInfo = result;

      // 1.获取用户信息后，立马检测动态路由中哪些是符合权限的，过滤出来
      const userAscynRoutes = filterAsyncRoutes(
        cloneDeep(allAsyncRoutes),
        result.routes
      );

      // 2.把过滤出来的动态路由插入到路由器中
      addRoutes(userAscynRoutes.concat(anyRoute));

      // 3.修改静态路由，让菜单也进行更新
      this.menuRoutes = staticRoutes.concat(userAscynRoutes,anyRoute);
      } catch (e) {
        //抛出请求异常
        return Promise.reject(e);
      }
    },

    //退出登录的方法
    async getLogout() {
      try {
        //发送退出登录请求
        await requestLogout();
        //作出清理工作
        this.reset();

        //退出登录的时候，把路由器中的路由全部清理掉
        // 获取所有路由记录的完整列表
        const routes =router.getRoutes();
        //遍历routes清理路由
        routes.forEach((item) =>{
          if(item.name) {
            router.removeRoute(item.name);
          }
        });
      } catch (e) {
        return Promise.reject(e);
      }
    },

    //退出登录之后,请求数据的方法
    reset() {
      // 删除local中保存的token
      removeToken();
      // 恢复原始的state的空值
      this.token = "";
      this.userInfo = {
        routes: [],
        buttons: [],
        roles: [],
        name: "",
        avatar: "",
      };
    },
  },
});
